import { SVG, registerWindow } from "@svgdotjs/svg.js";
import { createSVGWindow } from "svgdom";
import fs from "fs";
import xml2js from "xml2js";
import path from "path";
import { fileURLToPath } from "url";

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

const window = createSVGWindow();
const document = window.document;
registerWindow(window, document);

const parseColor = (colorStr) => {
  return colorStr.split(",").map(Number);
};

const createSVGElement = (element, svg) => {
  const type = element.name;
  const attrs = element.$;
  const commonProps = {
    fill: `rgb(${parseColor(attrs.fc || "255,255,255").join(",")})`,
    stroke: {
      color: `rgb(${parseColor(attrs.lc || "0,0,0").join(",")})}`,
      width: parseInt(attrs.lw, 10) || 1,
    },
  };

  const getArcPath = (cx, cy, rx, ry, a1, a2) => {
    const largeArcFlag = a2 - a1 > 180 ? 1 : 0;
    const startX = cx + rx * Math.cos((a1 * Math.PI) / 180);
    const startY = cy - ry * Math.sin((a1 * Math.PI) / 180);
    const endX = cx + rx * Math.cos((a2 * Math.PI) / 180);
    const endY = cy - ry * Math.sin((a2 * Math.PI) / 180);
    return `M ${startX} ${startY} A ${rx} ${ry} 0 ${largeArcFlag} 1 ${endX} ${endY}`;
  };

  const getTrianglePoints = (x, y, w, h) => {
    return [
      [x + w / 2, y], // Top point
      [x, y + h], // Bottom left point
      [x + w, y + h], // Bottom right point
    ];
  };

  const getParallelRectPoints = (x, y, w, h, dx) => {
    return [
      [x + dx, y], // Top left
      [x + w + dx, y], // Top right
      [x + w, y + h], // Bottom right
      [x, y + h], // Bottom left
    ];
  };

  const getDiamondPoints = (x, y, w, h) => {
    return [
      [x + w / 2, y], // Top point
      [x + w, y + h / 2], // Right point
      [x + w / 2, y + h], // Bottom point
      [x, y + h / 2], // Left point
    ];
  };

  switch (type) {
    case "pin":
      return svg
        .circle(parseInt(attrs.r, 10) * 2)
        .center(parseInt(attrs.cx, 10), parseInt(attrs.cy, 10))
        .fill(commonProps.fill)
        .stroke(commonProps.stroke);

    case "rect":
      return svg
        .rect(parseInt(attrs.w, 10), parseInt(attrs.h, 10))
        .move(parseInt(attrs.x, 10), parseInt(attrs.y, 10))
        .fill(commonProps.fill)
        .stroke(commonProps.stroke);

    case "line":
      return svg
        .line(
          parseInt(attrs.x1, 10),
          parseInt(attrs.y1, 10),
          parseInt(attrs.x2, 10),
          parseInt(attrs.y2, 10)
        )
        .stroke(commonProps.stroke);

    case "roundrect":
      return svg
        .rect(parseInt(attrs.w, 10), parseInt(attrs.h, 10))
        .move(parseInt(attrs.x, 10), parseInt(attrs.y, 10))
        .radius(parseInt(attrs.rx, 10), parseInt(attrs.ry, 10))
        .fill(commonProps.fill)
        .stroke(commonProps.stroke);

    case "circle":
      return svg
        .circle(parseInt(attrs.r, 10) * 2)
        .center(parseInt(attrs.cx, 10), parseInt(attrs.cy, 10))
        .fill(commonProps.fill)
        .stroke(commonProps.stroke);

    case "ellipse":
      return svg
        .ellipse(parseInt(attrs.rx, 10) * 2, parseInt(attrs.ry, 10) * 2)
        .center(parseInt(attrs.cx, 10), parseInt(attrs.cy, 10))
        .fill(commonProps.fill)
        .stroke(commonProps.stroke);

    case "circlearc":
      const circlearcPath = getArcPath(
        parseInt(attrs.cx, 10),
        parseInt(attrs.cy, 10),
        parseInt(attrs.r, 10),
        parseInt(attrs.r, 10),
        parseInt(attrs.a1, 10),
        parseInt(attrs.a2, 10)
      );
      return svg.path(circlearcPath).fill("none").stroke(commonProps.stroke);

    case "ellipsearc":
      const ellipsearcPath = getArcPath(
        parseInt(attrs.cx, 10),
        parseInt(attrs.cy, 10),
        parseInt(attrs.rx, 10),
        parseInt(attrs.ry, 10),
        parseInt(attrs.a1, 10),
        parseInt(attrs.a2, 10)
      );
      return svg.path(ellipsearcPath).fill("none").stroke(commonProps.stroke);

    case "polyline":
      const points = attrs.d
        .split(" ")
        .map((point) => point.split(",").map(Number));
      return svg.polyline(points).fill("none").stroke(commonProps.stroke);

    case "polygon":
      return svg
        .polygon(attrs.points)
        .fill(commonProps.fill)
        .stroke(commonProps.stroke);

    case "triangle":
      const trianglePoints = getTrianglePoints(
        parseInt(attrs.x, 10),
        parseInt(attrs.y, 10),
        parseInt(attrs.w, 10),
        parseInt(attrs.h, 10)
      );
      return svg
        .polygon(trianglePoints)
        .fill(commonProps.fill)
        .stroke(commonProps.stroke);

    case "parallelrect":
      const parallelRectPoints = getParallelRectPoints(
        parseInt(attrs.x, 10),
        parseInt(attrs.y, 10),
        parseInt(attrs.w, 10),
        parseInt(attrs.h, 10),
        parseInt(attrs.dx, 10)
      );
      return svg
        .polygon(parallelRectPoints)
        .fill(commonProps.fill)
        .stroke(commonProps.stroke);

    case "diamond":
      const diamondPoints = getDiamondPoints(
        parseInt(attrs.x, 10),
        parseInt(attrs.y, 10),
        parseInt(attrs.w, 10),
        parseInt(attrs.h, 10)
      );
      return svg
        .polygon(diamondPoints)
        .fill(commonProps.fill)
        .stroke(commonProps.stroke);

    case "text":
      return svg
        .text(attrs.ts)
        .move(parseInt(attrs.x, 10), parseInt(attrs.y, 10))
        .font({
          size: parseInt(attrs.fs, 10),
          family: attrs.ff || "Simsun",
          fill: commonProps.fill,
        })
        .stroke(commonProps.stroke);

    case "image":
      return svg
        .image(attrs.ahref)
        .size(parseInt(attrs.w, 10), parseInt(attrs.h, 10))
        .move(parseInt(attrs.x, 10), parseInt(attrs.y, 10));

    case "Text":
      return svg
        .text(attrs.ts)
        .move(parseInt(attrs.x, 10), parseInt(attrs.y, 10))
        .font({
          size: parseInt(attrs.fs, 10),
          family: attrs.ff || "Simsun",
          fill: `rgb(${parseColor(attrs.fc || "0,0,0").join(",")})`,
        })
        .stroke({
          color: `rgb(${parseColor(attrs.lc || "0,0,0").join(",")})}`,
          width: parseInt(attrs.lw, 10) || 1,
        });

    default:
      console.warn(`Unknown element type: ${type}`);
      return null;
  }
};

const processLayer = (layerElement, svg) => {
  Object.keys(layerElement).forEach((key) => {
    if (layerElement[key].length !== 0) {
      layerElement[key].forEach((element) => {
        const svgElement = createSVGElement({ name: key, $: element.$ }, svg);
        if (svgElement) {
          svg.add(svgElement);
        }
      });
    } else {
      console.warn(`Layer ${key} is empty`);
      throw new Error(`Layer ${key} is empty`);
    }
  });
};

const processElements = (elements, svg) => {
  elements.forEach((element) => {
    const width = parseInt(element.$.w, 10);
    const height = parseInt(element.$.h, 10);

    const group = svg.group();
    if (element.Layer) {
      element.Layer.forEach((layer) => processLayer(layer, group));
    }
    group.size(width, height).move(0, 0);
  });
};

const convertCIMToSVG = (inputFile, outputFile, errFile) => {
  fs.readFile(inputFile, "utf8", (err, data) => {
    if (err) {
      console.error(`Error reading file: ${err}`);
      fs.copyFile(inputFile, errFile, (err) => {
        if (err) {
          console.error(`Error copying file to err_svg: ${err}`);
        } else {
          console.log(`File with error copied to err_svg: ${errFile}`);
        }
      });
      return;
    }

    xml2js.parseString(data, (err, result) => {
      if (err) {
        console.error(`Error parsing XML: ${err}`);
        fs.copyFile(inputFile, errFile, (err) => {
          if (err) {
            console.error(`Error copying file to err_svg: ${err}`);
          } else {
            console.log(`File with error copied to err_svg: ${errFile}`);
          }
        });
        return;
      }

      // 自动处理所有元素类型
      const elements = [];

      if (result?.G) {
        Object.keys(result.G).forEach((key) => {
          elements.push(...(result.G[key] || []));
        });
      } else {
        console.error("No valid elements found");
      }
     

      if (elements.length === 0) {
        console.error("No valid elements found");
        fs.copyFile(inputFile, errFile, (err) => {
          if (err) {
            console.error(`Error copying file to err_svg: ${err}`);
          } else {
            console.log(
              `File with no valid elements copied to err_svg: ${errFile}`
            );
          }
        });
        return;
      }

      const svg = SVG(document.documentElement).size(1000, 1000); // 设置一个默认的画布大小

      try {
        processElements(elements, svg);
        // 获取边界框，并设置viewBox
        const bbox = svg.bbox();
        svg.viewbox(bbox.x, bbox.y, bbox.width, bbox.height);

        fs.writeFile(outputFile, svg.svg(), (err) => {
          if (err) {
            console.error(`Error writing SVG file: ${err}`);
            fs.copyFile(inputFile, errFile, (err) => {
              if (err) {
                console.error(`Error copying file to err_svg: ${err}`);
              } else {
                console.log(
                  `File with writing error copied to err_svg: ${errFile}`
                );
              }
            });
            return;
          }
          console.log(`SVG file saved to ${outputFile}`);
        });
      } catch (error) {
        // 将出错的保存到 err_svg 文件夹
        console.error(`Error processing elements: ${error}`);
        fs.copyFile(inputFile, errFile, (err) => {
          if (err) {
            console.error(`Error copying file to err_svg: ${err}`);
          } else {
            console.log(`File with error copied to err_svg: ${errFile}`);
          }
        });
      }
    });
  });
};

// 批量处理 symbols 文件夹中的文件
const symbolsFolder = path.join(__dirname, "symbols");
const svgsFolder = path.join(__dirname, "svgs");
const errSvgsFolder = path.join(__dirname, "err_svg");

// 创建输出文件夹（如果不存在）
if (!fs.existsSync(svgsFolder)) {
  fs.mkdirSync(svgsFolder);
}

if (!fs.existsSync(errSvgsFolder)) {
  fs.mkdirSync(errSvgsFolder);
}

// 读取 symbols 文件夹中的文件并转换
fs.readdir(symbolsFolder, (err, files) => {
  if (err) {
    console.error(`Error reading symbols folder: ${err}`);
    return;
  }

  files.forEach((file) => {
    const inputFile = path.join(symbolsFolder, file);
    const outputFile = path.join(svgsFolder, `${path.parse(file).name}.svg`);
    const errFile = path.join(errSvgsFolder, file);

    convertCIMToSVG(inputFile, outputFile, errFile);
  });
});
